
#include "NodeTop.h"
#include <sstream>
#include <iomanip>
#include "NodeLeaf.h"
#include "Model.h"

int NodeTop::topNodeNumber = 0;

using namespace std;

NodeTop::NodeTop(const QPoint &pos, QWidget* parent)
: Node(QString("top"), 1) {
    // make sure the parent pointer is set
    Q_CHECK_PTR(parent);
    setParent(parent);

    // set the position of this item on the math board
    move(pos);

    // set the name for this node
    std::stringstream ss(stringstream::in | stringstream::out);
    ss << "MathItem" << setfill('0') << setw(4) << ++topNodeNumber;
    setObjectName(QString::fromStdString(ss.str()));

    // set up a basic tree with just a NodeLeaf
    NodeLeaf* nl = new NodeLeaf();
    setSingleChild(nl);
    nl->upDateSize(); // this line must come after set child.
    nl->setFocus();

    show();
}

NodeTop::NodeTop(const QPoint &pos, QWidget* parent, Node* child)
: Node(QString("top"), 1) {
    // make sure the parent pointer is set
    Q_CHECK_PTR(parent);
    setParent(parent);

    // set the position of this item on the math board
    move(pos);

    // set the name for this node
    std::stringstream ss(stringstream::in | stringstream::out);
    ss << "MathItem" << setfill('0') << setw(4) << ++topNodeNumber;
    setObjectName(QString::fromStdString(ss.str()));

    // set child
    setSingleChild(child);
    child->upDateSize(); // this line must come after set child.
    child->setFocus();

    show();
}

void NodeTop::focusOut() {
    // the is a top level widget so remove if it is empty
    Q_ASSERT_X(getSingleChild(), "", "Expected a single child node.");
    // could catch this assert of a child that has focus is removed

    if (getSingleChild()->getNodeType() == "empty") {
        // then remove this
        setAttribute(Qt::WA_DeleteOnClose);
        close();
    }
}

void NodeTop::upDateSize() {
    adjustSize();
    updateGeometry();
}

int NodeTop::getInputPosition(bool&) const {
    bool found;
    return getSingleChild()->getInputPosition(found);
}

void NodeTop::setInputPosition(int& position) {
    getSingleChild()->setInputPosition(position);
}

std::vector<Node*> NodeTop::getEquals() const {
    Q_ASSERT_X(numChildren() == 1, "", "Expected one child.");
    Q_ASSERT_X(getSingleChild(), "", "Expected valid single child.");

    if (getSingleChild()->getNodeType() == "equal") {
        return getSingleChild()->getEquals();
    } else if (getSingleChild()->toCasString().size() > 0) {
        std::vector<Node*> v;
        v.push_back(getSingleChild());
        return v;
    } else {
        std::vector<Node*> v;
        return v;

    }
}

Controller* NodeTop::getController() {
    // now parent should be main window
    Model* parentNode = qobject_cast<Model*>(parentWidget());
    if (parentNode != 0 and parentNode != nullptr) {
        return parentNode->getController();
    } else {
        Q_ASSERT_X(0, "", "Parent is not a MainWindow.");
        return 0;
    }
}

void NodeTop::keyPressEvent(QKeyEvent *event) {
    // This method will get key events that are passed up from a leaf node.
    // The key events will be operator changing events.

    // unable to consistently find it after calling another method
    // so getting cursor position here
    bool b = false; // not used
    int cursorPosition = getInputPosition(b);

    if (event->text().size() == 1
            or event->key() == Qt::Key_Backspace
            or event->key() == Qt::Key_Delete) {
        insertKey(event, cursorPosition);
    } else if (event->key() == Qt::Key_Right
            or event->key() == Qt::Key_Left) {
        moveKey(event, cursorPosition);
    } else {
        qDebug("Unable to handle '%s' key in top node.", event->text().toAscii().data());
    }
}

void NodeTop::insertKey(QKeyEvent *event, int cursorPosition) {
    // get the current parse string
    QString parseString = toParseString();
    qDebug("old string: '%s'", parseString.toAscii().data());
    Q_ASSERT_X(cursorPosition <= parseString.length(), "", "Position not in string.");
    // take the key action on the string
    if (event->key() == Qt::Key_Backspace) {
        parseString.remove(--cursorPosition, 1);
    } else if (event->key() == Qt::Key_Delete) {
        parseString.remove(cursorPosition, 1);
    } else {
        parseString.insert(cursorPosition, event->text());
        cursorPosition += event->text().length();
    }
    qDebug("new string: '%s'", parseString.toAscii().data());
    // parse the new string
    Node* newNode = getController()->parse(parseString);
    Q_ASSERT_X(newNode != 0 and newNode != nullptr, "", "No new node from parser.");
    // remove all children in this top node
    delete getSingleChild();
    // save new tree content to this top node
    setSingleChild(newNode);
    // update the size
    upDateSize();
    // place cursor
    Q_ASSERT_X(cursorPosition <= toParseString().length(), "", "Position not in string.");
    setInputPosition(cursorPosition);
}

void NodeTop::moveKey(QKeyEvent *event, int cursorPosition) {
    int maxCursorPosition = toParseString().size();
    if (event->key() == Qt::Key_Right and cursorPosition < maxCursorPosition) {
        setInputPosition(++cursorPosition);
    } else if (event->key() == Qt::Key_Left and cursorPosition > 0) {
        setInputPosition(--cursorPosition);
    }
}
